
#include "esp32_manager.h"

#define IS_PAGE(page)   ((page)<(MaxPage))

#ifndef NULL
#   define NULL 0
#endif

void ESP32Manager::init(uint8_t pageMax, uint8_t pageStackSize) {
    MaxPage = pageMax;
    NewPage = 0;
    OldPage = 0;
    IsPageBusy = false;
    PageList = new PageList_T[MaxPage];
    for(uint8_t page = 0; page < MaxPage; page++)
    {
        PageClear(page);
    }

    PageStackSize = pageStackSize;
    PageStack = new uint8_t[PageStackSize];
    PageStackClear();
}

void ESP32Manager::dnit() {
    delete[] PageList;
    delete[] PageStack;
}

bool ESP32Manager::PageClear(uint8_t pageID) {
    if(!IS_PAGE(pageID)) return false;
    PageList[pageID].SetupCallback = NULL;
    PageList[pageID].LoopCallback = NULL;
    PageList[pageID].ExitCallback = NULL;
    PageList[pageID].EventCallback = NULL;
    return true;
}

bool ESP32Manager::PageRegister(
    uint8_t pageID,
    CallbackFunction_t setupCallback,
    CallbackFunction_t loopCallback,
    CallbackFunction_t exitCallback,
    EventFunction_t eventCallback
) {
    if(!IS_PAGE(pageID)) return false;
    PageList[pageID].SetupCallback = setupCallback;
    PageList[pageID].LoopCallback = loopCallback;
    PageList[pageID].ExitCallback = exitCallback;
    PageList[pageID].EventCallback = eventCallback;
    return true;
}

void ESP32Manager::PageEventTransmit(int key, int event) {
    if(PageList[NowPage].EventCallback != NULL)
        PageList[NowPage].EventCallback(key, event);
}

void ESP32Manager::PageChangeTo(uint8_t pageID) {
    if(!IS_PAGE(pageID)) return;
    if(!IsPageBusy) {
        NextPage = NewPage = pageID;
        IsPageBusy = true;
    }
}

int8_t ESP32Manager::PagePush(uint8_t pageID) {
    if(!IS_PAGE(pageID)) return -1;
    if(IsPageBusy) return -1; 
    if(PageStackTop >= PageStackSize - 1) return PageStackTop;
    if(pageID == PageStack[PageStackTop]) return PageStackTop;

    PageStackTop++;
    PageStack[PageStackTop] = pageID;
    PageChangeTo(PageStack[PageStackTop]);
    return PageStackTop;
}

int8_t ESP32Manager::PagePop() {
    if(IsPageBusy) return -1; 
    if(PageStackTop == 0) return 0;
    if(PageStackTop == 1) return 1;
    PageStack[PageStackTop] = 0;
    
    PageStackTop--;
    PageChangeTo(PageStack[PageStackTop]);
    return PageStackTop;
}

void ESP32Manager::PageStackClear() {
    if(IsPageBusy) return; 
    for(uint8_t i = 0; i < PageStackSize; i++) {
        PageStack[i] = 0;
    }
    PageStackTop = 0;
}

void ESP32Manager::Running() {
    if(NewPage != OldPage) {
        IsPageBusy = true;
        if(PageList[OldPage].ExitCallback != NULL && IS_PAGE(OldPage))
            PageList[OldPage].ExitCallback();
        LastPage = OldPage;
        NowPage = NewPage;
        if(PageList[NewPage].SetupCallback != NULL && IS_PAGE(NewPage))
            PageList[NewPage].SetupCallback();
        OldPage = NewPage;
    }
    else {
        IsPageBusy = false;
        if(PageList[NowPage].LoopCallback != NULL && IS_PAGE(NowPage))
            PageList[NowPage].LoopCallback();
    }
}
